﻿using System;

namespace NeuralNetworks.Math
{
	/// <summary>
	/// Класс диапазона значений.
	/// </summary>
	/// <typeparam name="T">Тип должен реализовывать интерфйес <see cref="IComparable{T}"/></typeparam>
	public class Range<T> where T : IComparable<T>
	{
		#region Частные поля

		/// <summary>
		/// Минимальное значение диапазона
		/// </summary>
		protected T _min;

		/// <summary>
		/// Макимальное значение диапазона
		/// </summary>
		protected T _max;

		/// <summary>
		/// Включается ли в диапазон минимальное его значение
		/// </summary>
		protected bool _minIncluded;

		/// <summary>
		/// Включается ли в диапазон минимальное его значение
		/// </summary>
		protected bool _maxIncluded;

		#endregion

		#region Свойства

		/// <summary>
		/// Минимальное значение диапазона
		/// </summary>
		/// <exception cref="ArgumentOutOfRangeException"/>
		public T Min
		{
			get { return _min; }
			set
			{
				if (value.CompareTo(_max) > 0) throw new ArgumentOutOfRangeException("value", "Min can't be grate than Max");
				_min = value;
			}
		}

		/// <summary>
		/// Максимальное значение диапазона
		/// </summary>
		/// <exception cref="ArgumentOutOfRangeException"/>
		public T Max
		{
			get { return _max; }
			set
			{
				if (value.CompareTo(_min) < 0) throw new ArgumentOutOfRangeException("value", "Max can't be less than Min");
				_max = value;
			}
		}

		/// <summary>
		/// Включается ли в диапазон минимальное его значение
		/// </summary>
		public bool IsMinIncluded
		{
			get { return _minIncluded; }
			set { _minIncluded = value; }
		}

		/// <summary>
		/// Включается ли в диапазон минимальное его значение
		/// </summary>
		public bool IsMaxIncluded
		{
			get { return _maxIncluded; }
			set { _maxIncluded = value; }
		}

		#endregion

		#region Конструкторы

		private Range()
		{
			IsMaxIncluded = true;
			IsMinIncluded = true;
		}

		/// <summary>
		/// Конструктор объекта класса <see cref="Range{T}"/>
		/// </summary>
		/// <param name="min">Минимальное значение диапазона.</param>
		/// <param name="max">Максимальное значение диапазона.</param>
		/// <remarks>По-умолчанию границы в диапазон включаются.</remarks>
		public Range(T min, T max)
			: this()
		{
			_min = min;
			_max = max;
		}

		#endregion

		#region Публичные методы

		/// <summary>
		/// Конвертирует значения диапазона в строку.
		/// </summary>
		/// <returns>Строковой вид диапазона</returns>
		public override string ToString()
		{
			return (IsMinIncluded ? "[ " : "( ") + Min + " ; " + Max + (IsMaxIncluded ? " ]" : " )");
		}

		/// <summary>
		/// Находится ли значение внутри диапазона
		/// </summary>
		/// <param name="value">Проверяемое значение</param>
		/// <returns>True - находися; False - не находися.</returns>
		public bool IsInside(T value)
		{
			if (value.CompareTo(_min) < 0 | value.CompareTo(_max) > 0) return false;
			if ((!IsMinIncluded & value.CompareTo(_min) == 0) | (!IsMaxIncluded & value.CompareTo(_max) == 0)) return false;
			return true;
		}
		
		public bool IsInside(Range<T> range)
		{
			throw new NotImplementedException();
		}

		public bool IsOverlapping(Range<T> range)
		{
			throw new NotImplementedException();
		}
		
		#endregion
	}
}
